//
// Created by 罗外林 on 2024/1/1.
//

#include "BLProgram.h"

#include "./Log.h"

#define LOG_TAG "BLProgram"

BLProgram::BLProgram(const char *vShaderString, const char *fShaderString) {


    program = glCreateProgram();

    if (!complileShader(&vertShader, GL_VERTEX_SHADER, vShaderString)) {
        LOGE("Failed to compile vertex shader");
    }

    if (!complileShader(&fragShader, GL_FRAGMENT_SHADER, fShaderString)) {
        LOGE("Failed to compile fragment shader");
    }

    glAttachShader(program, vertShader);
    glAttachShader(program, fragShader);
}

void BLProgram::use() {
    glUseProgram(program);
}

bool BLProgram::link(){
    GLint status;
    glLinkProgram(program);

    glGetProgramiv(program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE)
        return false;

    if (vertShader) {
        glDeleteShader(vertShader);
        vertShader = 0;
    }
    if (fragShader) {
        glDeleteShader(fragShader);
        fragShader = 0;
    }
    return true;
}

GLuint BLProgram::uniformIndex(std::string uniformName) {
    return glGetUniformLocation(program, uniformName.c_str());
}

GLuint BLProgram::attributeIndex(std::string attributeName) {
    auto it = find(attributes.begin(), attributes.end(), attributeName);
    if (it != attributes.end()) {
        int index = distance(attributes.begin(), it);
        return index;
    }
    return -1;
}

void BLProgram::addAttribute(std::string attributeName) {
    attributes.push_back(attributeName);
}

bool BLProgram::complileShader(GLuint *shader, GLenum type, std::string shaderString) {
    GLint status;
    const GLchar *source;
    source = (GLchar *)shaderString.c_str();
    if (!source) {
        return false;
    }

    *shader = glCreateShader(type);
    glShaderSource(*shader, 1, &source, NULL);
    glCompileShader(*shader);

    glGetShaderiv(*shader, GL_COMPILE_STATUS, &status);

    if (status != GL_TRUE) {
        GLint logLength;
        glGetShaderiv(*shader, GL_INFO_LOG_LENGTH, &logLength);
        if (logLength > 0) {
            GLchar *log = (GLchar *)malloc(logLength);
            glGetShaderInfoLog(*shader, logLength, &logLength, log);
            if (shader == &vertShader)
            {
                LOGE("vertex Shader log is:%s", log);
            }
            else
            {
                LOGE("fragment Shader log is:%s", log);
            }
            free(log);
        }
    }
    return status == GL_TRUE;

}
